/* linbox/matrix/archetype.h
 * Copyright (C) 2001 B. David Saunders,
 *               2001-2002 Bradford Hovinen,
 *               2002 Zhendong Wan
 *
 * Written by B. David Saunders <saunders@cis.udel.edu>,
 *            Bradford Hovinen <hovinen@cis.udel.edu>,
 *            Zhendong Wan <wan@mail.eecis.udel.edu>
 *
 * Borrowed from dense-base.h by Bradford Hovinen
 * evolved from dense-matrix.h by -bds, Zhendong Wan
 *
 * This holds the "directly represented" matrix archetype. It is provided here
 * only for reference; it does not provide any useful functionality. See the
 * other headers in this directory for useful classes.
 *
 * --------------------------------------------------------
 *
 * 
 * ========LICENCE========
 * This file is part of the library LinBox.
 * 
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *
 */

/*!@file matrix/archetype.h
 * @ingroup matrix
 * @brief NO DOC
 * @see \ref Archetypes
 */

#ifndef __LINBOX_matrix_archetype_H
#define __LINBOX_matrix_archetype_H

#include <iostream>
#include <vector>
#include <fstream>

#include "linbox/blackbox/archetype.h"

namespace LinBox
{

	/** @brief Directly-represented matrix archetype
	 *
	 * This archetype gives the common interface for matrices that have direct
	 * representations. The matrices are required to provide iterators to access and
	 * manipulate their entries, but not any matrix-matrix or matrix-vector
	 * arithmetic. That is, they are pure containers. As such, they are only
	 * parameterized on the element type, not on the field type.
	 */

	template <class _Element>
	class MatrixArchetype {
	public:

		typedef _Element Element;

		/** Empty Constructor.
		*/
		MatrixArchetype ();

		/** Constructor with size
		 * @param  m  row dimension
		 * @param  n  column dimension
		 */
		MatrixArchetype (size_t m, size_t n);

		/** Copy constructor
		*/
		MatrixArchetype (const MatrixArchetype &M);

		/** Operator =
		*/
		MatrixArchetype& operator= (const MatrixArchetype& M);

		/** Get the number of rows in the matrix
		 * @return Number of rows in matrix
		 */
		size_t rowdim () const;

		/** Get the number of columns in the matrix
		 * @return Number of columns in matrix
		 */
		size_t coldim () const;

		/** \brief Resize the matrix to the given dimensions.
		 *
		 * The state of the matrix's entries after a call to this method is
		 * undefined.
		 *
		 * This interface is optional; a matrix can omit it if it makes no sense
		 * in the context.
		 *
		 * @param m Number of rows
		 * @param n Number of columns
		 */
		void resize (size_t m, size_t n);

		/** @name Input and output
		*/

		//@{

		/** Read the matrix from an input stream.
		 * @param file Input stream from which to read
		 * @param F Field over which to read
		 */
		template <class Field>
		std::istream &read (std::istream &file, const Field &F);

		/** Write the matrix to an output stream.
		 * @param os Output stream to which to write
		 * @param F Field over which to write
		 */
		template <class Field>
		std::ostream &write (std::ostream &os, const Field &F) const;

		//@}

		/**
		 * @name Access to matrix elements
		*/

		//@{

		/** Set the entry at the (i, j) position to a_ij.
		 * @param i Row number, 0...rowdim () - 1
		 * @param j Column number 0...coldim () - 1
		 * @param a_ij Element to set
		 */
		const Element& setEntry (size_t i, size_t j, const Element &a_ij);

		/** Get a writeable reference to the entry in the (i, j) position.
		 * @param i Row index of entry
		 * @param j Column index of entry
		 * @return Reference to matrix entry
		 */
		Element &refEntry (size_t i, size_t j);

		/** Get a read-only reference to the entry in the (i, j) position.
		 * @param i Row index
		 * @param j Column index
		 * @return Const reference to matrix entry
		 */
		const Element &getEntry (size_t i, size_t j) const;

		/** Copy the (i, j) entry into x, and return a reference to x.
		 * This form is more in the Linbox style and is provided for interface
		 * compatibility with other parts of the library
		 * @param x Element in which to store result
		 * @param i Row index
		 * @param j Column index
		 * @return Reference to x
		 */
		Element &getEntry (Element &x, size_t i, size_t j) const;

		/* N.B. A matrix type may omit either one, but not both, of the
		 * following two iterator types. If one type is omitted, then certain
		 * restrictions on matrix-matrix arithmetic apply; see
		 * @ref MatrixDomain
		 */

		/** Column of rows iterator.
		 * The column of rows iterator traverses the rows of the
		 * matrix in ascending order. Dereferencing the iterator yields
		 * a row vector in dense format
		 */

		//@{
		class Row;
		class ConstRow;
		class RowIterator;
		class ConstRowIterator;

		/// rowBegin
		RowIterator rowBegin ();
		/// rowEnd
		RowIterator rowEnd ();
		/// const rowBegin
		ConstRowIterator rowBegin () const;
		/// const rowEnd
		ConstRowIterator rowEnd () const;
		//@}

		/** Row of columns iterator.
		 * The row of columns iterator traverses the columns of the
		 * matrix in ascending order. Dereferencing the iterator yields
		 * a column vector in dense format
		 */
		//@{
		class Col;
		class ConstCol;
		class ColIterator;
		class ConstColIterator;

		typedef Col Column;
		typedef ConstCol ConstColumn;
/// colBegin
		ColIterator colBegin ();
		/// colEnd
		ColIterator colEnd ();
		/// const colBegin
		ConstColIterator colBegin () const;
		/// const colEnd
		ConstColIterator colEnd () const;
		//@}

		/**  Iterator.
		 * The raw iterator is a method for accessing all entries in the matrix
		 * in some unspecified order. This can be used, e.g. to reduce all
		 * matrix entries modulo a prime before passing the matrix into an
		 * algorithm.
		 */
		//@{
		class Iterator;
		class ConstIterator;

		Iterator Begin ();
		Iterator End ();
		ConstIterator Begin () const;
		ConstIterator End () const;
		//@}

		/** Like the raw iterator, the indexed iterator is a method for
		 * accessing all entries in the matrix in some unspecified order.
		 *
		 * At each position of the the indexed iterator, it also provides
		 * the row and column indices of the currently referenced entry.
		 * This is provided through it's \c rowIndex() and \c colIndex() functions.
		 */
		//@{
		class IndexedIterator;
		typedef const IndexedIterator ConstIndexedIterator;

		IndexedIterator IndexedBegin();
		IndexedIterator IndexedEnd();
		ConstIndexedIterator IndexedBegin() const;
		ConstIndexedIterator IndexedEnd() const;
		//@}

		/** Retrieve a reference to a row.
		 * Since rows may also be indexed, this allows A[i][j] notation
		 * to be used.
		 *
		 * This may be omitted by an implementation if no Row type is available
		 *
		 * @param i Row index
		 */
		Row operator[] (size_t i);
		/// const version
		ConstRow operator[] (size_t i) const;

		//@}

		/** @name Computing matrix information
		*/

		//@{

		/** Compute the column density, i.e. the number of entries per column
		*/
		template <class Vector>
		Vector &columnDensity (Vector &v) const;

		/** Compute the transpose
		*/
		MatrixArchetype &transpose (MatrixArchetype &M) const;

		//@}

	protected:

		std::vector<Element>  _rep;
		size_t                _rows, _cols;
	};

	template <class Element>
	struct MatrixTraits< MatrixArchetype<Element> >
	{
		typedef MatrixArchetype<Element> MatrixType;
		typedef typename MatrixCategories::RowColMatrixTag MatrixCategory;
	};

} // namespace LinBox

#endif // __LINBOX_matrix_archetype_H

// Local Variables:
// mode: C++
// tab-width: 4
// indent-tabs-mode: nil
// c-basic-offset: 4
// End:
// vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
